マイコン/パソコン系の最も最初のグラフィック描画システムは、おそらくクリッピングの機能すらろくに持たない極めて貧弱なものだったと思います。それこそ、「画面を消す」「点を打つ」「点を消す」ぐらいの機能しかないものです。
これが、徐々に進化を始め、16bit版Windowsの描画システムであるGDIでは、クリッピングができるだけでなく、座標系のスケールを自由に取れるようになりました。つまり画面上の1ピクセルが指定座標数値のどれぐらいに対応するかが自由に指定できるようになったわけです。これによって、描画データが持つ本来の数値を渡しつつ、画面上では適切なピクセル数で描くということが可能になりました。(いやまて、N88-BASICぐらいで、既にウィンドウやビューポートの機能を持っていて可能だったか?)
更にこれが16bit版のOS/2(当時はWindowsの後継OS)になると、座標変換行列が指定可能になり、それこそ好きなように座標系を変形させることができたわけです。
ちなみに、この「座標変換行列が指定可能」という機能を知ったときには痺れましたねぇ。本当にまともなスピードで処理できるのか疑問に思いましたが、機能としては夢があって魅力があると思いました。
ベクトルデータは座標値を演算するだけで変形に対応できますが、高速描画のために特殊な構造になっていて、デバイスドライバレベルで描かれる文字と、データ量が大きく、これまた特殊な構造で処理されるビットマップは、座標系の変換を指定しても、機能してくれなかったように思います。
ArgumentExceptionは、どのようなケースで出るのかドキュメントに記述が無く、詳細不明です。何となく不都合があるパラメータがあるのだろうということは推測できますが、どこからどこまでの値に不都合が出るのか、詳細不明です。
OutOfMemoryExceptionの方は、そもそも出る理由が不明です。メモリ不足ということはありませんし、そのまま継続して次のフレームの描画に成功していることから考えて、何らかのシステムリソース不足とも思えません。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace RotateTransform001
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private float param1 = 0.0f;
private float param2 = 0.0f;
private float param3 = 0.0f;
private float param4 = 0.0f;
private float param5 = 0.0f;
private float param6 = 0.0f;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
try
{
int centerX = this.pictureBox1.Width / 2;
int centerY = this.pictureBox1.Height / 2;
using (System.Drawing.Drawing2D.Matrix transformMatrix =
new System.Drawing.Drawing2D.Matrix(
(float)Math.Cos(param3 / 360.0f * Math.PI),
(float)Math.Sin(param4 / 360.0f * Math.PI),
-(float)Math.Sin(param5 / 360.0f * Math.PI),
(float)Math.Cos(param6 / 360.0f * Math.PI), 0, 0
))
{
e.Graphics.TranslateTransform(centerX, centerY);
e.Graphics.MultiplyTransform(transformMatrix);
e.Graphics.DrawRectangle(Pens.Blue, 0, 0, 10, 10);
e.Graphics.DrawImage(this.pictureBox2.Image,
-this.pictureBox2.Image.Width / 2,
-this.pictureBox2.Image.Height / 2);
e.Graphics.ResetTransform();
e.Graphics.TranslateTransform(centerX, centerY);
e.Graphics.MultiplyTransform(transformMatrix);
const string message = "ROTATING";
e.Graphics.DrawString(message, new Font("Arial", 20.0f),
Brushes.Black, new PointF(0.0f, 0.0f));
e.Graphics.DrawString(message, new Font("Arial", 20.0f),
Brushes.Magenta, new PointF(1.0f, 1.0f));
}
}
catch (System.Exception ex)
{
this.label2.Text = (int.Parse(this.label2.Text) + 1).ToString();
this.textBox1.Text = DateTime.Now.ToString() + ":\r\n"
+ ex.ToString() + "\r\n\r\n" + this.textBox1.Text;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
param1 = (param1 + 5.0f);
param2 = (param2 - 4.0f);
param3 = (param3 + 3.5f);
param4 = (param4 + 3.0f);
param5 = (param5 + 2.5f);
param6 = (param6 + 2.0f);
this.pictureBox1.Invalidate();
}
}
}